from flask import current_app
from flask_restx import Namespace, Resource, fields
from flask_jwt_extended import jwt_required
from flask_security.utils import hash_password

from ..extensions import db
from ..models import Role, User
from ..utils import require_role

ns = Namespace("users", description="用户管理接口")

role_model = ns.model(
    "Role",  # 用户角色模型
    {
        "id": fields.Integer,
        "name": fields.String,
    },
)

user_model = ns.model(
    "User",  # 用户响应模型
    {
        "id": fields.Integer,
        "email": fields.String,
        "roles": fields.List(fields.String),
    },
)

create_user_model = ns.model(
    "CreateUser",  # 创建用户请求模型
    {
        "email": fields.String(required=True, description="用户邮箱"),
        "password": fields.String(required=True, description="初始密码"),
        "roles": fields.List(fields.String, description="角色列表", default=["user"]),
    },
)


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: UserCollection
#  * 作用: 提供用户集合的查询与创建接口
#  * 参数:
#  *   @param 无 类实例化由 Flask-RESTX 管理
#  * 返回: 无
#  * 备注: 所有操作需管理员角色
#  */
@ns.route("")
class UserCollection(Resource):
    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: get
    #  * 作用: 列出系统中的全部用户及其角色
    #  * 参数:
    #  *   @param self 当前资源实例
    #  * 返回: 用户信息列表
    #  * 备注: 需要 admin 角色
    #  */
    @jwt_required()
    @ns.marshal_list_with(user_model)
    def get(self):
        require_role(ns, "admin")
        users = User.query.all()
        return [
            {"id": u.id, "email": u.email, "roles": [role.name for role in u.roles]} for u in users
        ]

    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: post
    #  * 作用: 创建新用户并分配相应角色
    #  * 参数:
    #  *   @param self 当前资源实例
    #  * 返回: 新创建用户的详细信息
    #  * 备注: 检查邮箱唯一性，不存在则自动补全角色
    #  */
    @jwt_required()
    @ns.expect(create_user_model, validate=True)
    @ns.marshal_with(user_model, code=201)
    def post(self):
        require_role(ns, "admin")
        payload = ns.payload
        datastore = current_app.extensions["security"].datastore

        if datastore.find_user(email=payload["email"].lower()):
            ns.abort(409, "用户已存在")

        roles = []
        for role_name in payload.get("roles", ["user"]):
            role = datastore.find_role(role_name)
            if not role:
                role = datastore.create_role(name=role_name)
            roles.append(role)

        user = datastore.create_user(
            email=payload["email"].lower(),
            password=hash_password(payload["password"]),
            roles=roles,
        )
        db.session.commit()

        return {
            "id": user.id,
            "email": user.email,
            "roles": [role.name for role in user.roles],
        }, 201


# /**
#  * 作者: "test_LH"
#  * 日期: 2025-10-11
#  * 名称: UserItem
#  * 作用: 提供单个用户的查询与删除操作
#  * 参数:
#  *   @param 无 类实例化由 Flask-RESTX 管理
#  * 返回: 无
#  * 备注: 所有操作需管理员角色
#  */
@ns.route("/<int:user_id>")
@ns.param("user_id", "用户 ID")
class UserItem(Resource):
    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: get
    #  * 作用: 根据用户 ID 返回用户详情
    #  * 参数:
    #  *   @param self 当前资源实例
    #  *   @param user_id 路径中的用户主键
    #  * 返回: 用户的基本信息字典
    #  * 备注: 用户不存在时返回 404
    #  */
    @jwt_required()
    @ns.marshal_with(user_model)
    def get(self, user_id: int):
        require_role(ns, "admin")
        user = User.query.get_or_404(user_id, description="用户不存在")
        return {
            "id": user.id,
            "email": user.email,
            "roles": [role.name for role in user.roles],
        }

    # /**
    #  * 作者: "test_LH"
    #  * 日期: 2025-10-11
    #  * 名称: delete
    #  * 作用: 删除指定用户并提交数据库事务
    #  * 参数:
    #  *   @param self 当前资源实例
    #  *   @param user_id 路径中的用户主键
    #  * 返回: 空响应，状态码 204
    #  * 备注: 删除前需校验用户存在性
    #  */
    @jwt_required()
    def delete(self, user_id: int):
        require_role(ns, "admin")
        datastore = current_app.extensions["security"].datastore
        user = datastore.find_user(id=user_id)
        if not user:
            ns.abort(404, "用户不存在")
        datastore.delete_user(user)
        db.session.commit()
        return "", 204
